Android 平台智能指针使用与分析

9/25/2023

本文基于 aosp android12_r28 分支分析。

C/C++ 指针在使用上主要存在以下两类难点:

  • 野指针问题
    • C++ 的熟练工通常会把刚声明的指针赋值为 NULL。声明而未赋值的指针,有可能指向了一个未知的地址,成为野指针,操作这个指针可能会带来程序错误与崩溃。
    • 将对象 delete 后,C++ 的熟练工会将指针赋值为 NULL,不然这个指针也会成为野指针
    • 当多个指针都指向了对象 A,当某个地方将对象 A delete 后,操作其他地方的指针,就是对一个非法的内存进行操作了
  • 当使用了 malloc/new 分配了内存,都需要使用 free/delete 回收这块内存,当程序变得复杂起来,很多时候,程序员就会忘记回收内存,导致内存泄漏。

在 Android 中实现了一套完善的智能指针机制来简化 C++ 中指针的使用,以规避以上的两类难点。

# 1.智能指针的使用

在 Android 中,智能指针是一个类/对象,分为强引用(有的地方也叫强指针) sp 与弱引用(有的地方也叫弱指针) wp,以下是 wp 与 sp 的基本使用:

# 1.1 强引用 sp 基本使用

强引用简化了指针的使用,让我们不用考虑野指针问题与回收内存操作,其基本使用如下:


// 0. 需要使用智能指针的类必须继承自 RefBase
class Xpublic RefBase
{
    void test() 
    {
        //......
    }
}

{   // 作用域开始
    // 1.被管理的指针
    X* p = new X();  
    // 2.构建强引用
    sp<X> spX(p);   // sp<X> spX = new X()  这样也行,注意不要写成 sp<X> spX = new sp<X>() 
    // 3.通过强引用,操作指针指向的对象
    spX->test();
}   // 作用域结束,调用强引用对象的析构函数,释放掉 p 指针指向的内存
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

可以看出,在使用上,sp 就和指针一样,而且 sp 代为管理了 p 指针的回收操作,不需要我们手动回收内存。

# 1.2 弱引用 wp 的基本使用

默认情况下,弱引用用于记录一个指针值,不能通过弱引用来访问弱引用内部指针指向的对象,也就是说不能通过弱引用来调用成员函数或读写成员变量。要想使用弱引用内部指针所指向的对象,需首先将弱引用升级为强指针(通过 wp 类所提供的 promote() 方法)后,在通过强指针操作目标对象。

弱引用内部指针所指向的对象可能在其它地方被销毁了,如果该对象已经被销毁,wp 的 promote() 方法返回的 sp 对象的内部指针为空,这样就能避免出现地址访问错误的情况。其使用方法如下:

{   // 作用域开始
    // 1.被管理的指针
    X* p = new X();
    // 2.构建一个弱引用
    wp<X> wpX(p);
    // 3. 不能直接通过弱引用使用对象,升级为强指针再使用
    sp<X> spX2 = wpx.promote()
    if(spX2 != NULL)  // spX2 与 NULL 不是同一类型, 这里重载了 !=,实际比较的是 spX2 内部指针与 NULL 是否相等 
    {
        spX2->test();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12

需要注意的是 if(spX2 != NULL) ,spX2 与 NULL 不是同一类型, 这里重载了 !=,实际比较的是 spX2 内部指针与 NULL 是否相等

# 1.3 智能指针的两种模式

智能指针有两种模式: OBJECT_LIFETIME_STRONG 和 OBJECT_LIFETIME_WEAK,可以通过 void RefBase::extendObjectLifetime(int32_t mode) 函数切换模式,可传入的参数有:

// system/core/libutils/include/utils/RefBase.h
enum {
    //强引用控制
    OBJECT_LIFETIME_STRONG  = 0x0000,
    //弱引用控制
    OBJECT_LIFETIME_WEAK    = 0x0001,
    //OBJECT_LIFETIME_MASK 是一个掩码值,后面会使用 flag&OBJECT_LIFETIME_MASK 的形式来获取 flag 的最低位数值
    OBJECT_LIFETIME_MASK    = 0x0001
};
1
2
3
4
5
6
7
8
9

这个函数通常在被管理的目标类的构造函数中调用:

// frameworks/native/libs/binder/BpBinder.cpp
BpBinder::BpBinder(Handle&& handle)
      : mStability(0),
        mHandle(handle),
        mAlive(true),
        mObitsSent(false),
        mObituaries(nullptr),
        mTrackedUid(-1) {
    // 调用函数修改智能指针模式
    extendObjectLifetime(OBJECT_LIFETIME_WEAK);
}
1
2
3
4
5
6
7
8
9
10
11

绝大多数情况下都是使用默认的 OBJECT_LIFETIME_STRONG 模式,两种模式的差异,我们会在下一节的源码分析中来做解释。

# 1.4 Android12 中的一点变化

以上是 Android 平台智能指针的传统用法,Android12 中更新了一种全新的使用方法:

// frameworks/native/libs/binder/ProcessState.cpp

sp<ProcessState> ProcessState::init(const char *driver, bool requireDefault)
{
    //......
    static sp<ProcessState> gProcess;
    //......
    // 在 make 内部会使用参数 driver,new 一个 ProcessState 对象
    // 构建一个 sp<ProcessState> 对象,其内部 new 一个 ProcessState 对象,在将成员变量 m_ptr 指针指向它 
    gProcess = sp<ProcessState>::make(driver);
    //......
    return gProcess;
}
1
2
3
4
5
6
7
8
9
10
11
12
13

上面的代码的 make 函数中,构建一个 sp 对象,其内部构建了一个新对象 new ProcessState(driver),再将 sp 的成员变量 m_ptr 指针指向这个新对象。 总结一下就是用 make 代替了之前的 new 操作。

# 2.智能指针的原理与源码分析

# 2.1 基本原理

在 C++ 中,对象可以分为栈对象与堆对象:

void test() {
    Sheep sheep;   //栈对象,作用域结束后,会调用对象的析构函数
    Sheep* pSheep = new Sheep(); //堆对象,需要手动释放
    delete pSheep; //释放 pSheep 指向的对象
    pSheep = 0; //将pSheep指向NULL,防止造成野指针问题
}
1
2
3
4
5
6

在一个作用域中,对象分为了两类:

  • 栈对象:直接声明的对象,例如上面的 Sheep sheep;
  • 堆对象:通过指针和 new 构建的对象,例如上面的 Sheep* pSheep = new Sheep()

当栈对象所在的作用域结束时,栈对象的析构函数会被执行,智能指针就是利用了这一点来实现内存自动释放功能的:

  • 引用对象是一个栈对象,内部有一个指针,指向被管理的对象
  • 被管理对象内部保存有一个引用计数值
  • 当增加一个引用对象时,引用计数值加 1
  • 当引用对象所在作用域执行完后,会执行到引用对象的析构函数,在析构函数中,引用计数减 1,执行完减 1 操作后,如果引用计数值等于 0,那么释放引用内部指针指向的对象

以上就是智能指针的基本原理,实际的源码会复杂一些:

# 2.2 强引用源码分析

在 1.1 节的示例代码中,我们定义了一个 X 类,X 类继承自 RefBase,当执行到 X* p = new X() 代码时,会执行到父类 RefBase 的构造函数:

// system/core/libutils/RefBase.cpp
RefBase::RefBase()
    : mRefs(new weakref_impl(this))
{
}

//上面代码会执行到 weakref_impl 构造函数
explicit weakref_impl(RefBase* base)
        : mStrong(INITIAL_STRONG_VALUE)
        , mWeak(0)
        , mBase(base)
        , mFlags(0)
    {
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14

RefBase 构造函数会先 new 一个 weakref_impl 对象出来然后赋值给 RefBase 的 mRefs 成员。weakref_impl 用于智能指针的管理,内部保存了智能指针需要的重要数据:

  • mBase:RefBase* const 类型指针,指向需要管理的对象,也就是 RefBase 构造函数中传入的 this,即当前对象指针

  • mStrong:强引用计数,初始值为 INITIAL_STRONG_VALUE 即 0x1000000

  • mWeak:弱引用计数,初始值为 0

  • mFlags:一个标记值,标识是强引用控制还是弱引用控制,默认是 0 ,表示强引用控制,其可选值如下:

    // system/core/libutils/include/utils/RefBase.h
    enum {
        //强引用控制
        OBJECT_LIFETIME_STRONG  = 0x0000,
        //弱引用控制
        OBJECT_LIFETIME_WEAK    = 0x0001,
        //OBJECT_LIFETIME_MASK 是一个掩码值,后面会使用 flag&OBJECT_LIFETIME_MASK 的形式来获取 flag 的最低位数值
        OBJECT_LIFETIME_MASK    = 0x0001
    };
    
    // system/core/libutils/RefBase.cpp
    // mFlags 的值通常在目标对象(示例中的 X 类)的构造函数中通过 extendObjectLifetime 函数修改
    void RefBase::extendObjectLifetime(int32_t mode)
    {
        mRefs->mFlags.fetch_or(mode, std::memory_order_relaxed);
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16

当 1.1 节的示例代码执行到 sp<X> spX(p); 时,就会调用到 sp 的构造函数:

// system/core/libutils/include/utils/StrongPointer.h
template<typename T>
sp<T>::sp(T* other)
        : m_ptr(other) { // m_ptr 是一个指针,指向需要管理的对象
    if (other) {
        check_not_on_stack(other); // 确保 other 是一个堆对象
        other->incStrong(this);    // 增加强引用计数
    }
}
1
2
3
4
5
6
7
8
9

主要执行了如下操作:

  • m_ptr 指向被管理对象
  • incStrong 增加强引用计数

接着我们来看一看 incStrong 的具体实现:

// system/core/libutils/RefBase.cpp
void RefBase::incStrong(const void* id) const
{
    weakref_impl* const refs = mRefs;  //拿到内部数据对象
    refs->incWeak(id); //增加弱引用计数
 
    refs->addStrongRef(id); // 由 DEBUG_REFS 控制,release 版本什么也不做
    //强引用计数加 1
    const int32_t c = refs->mStrong.fetch_add(1, std::memory_order_relaxed);
    ALOG_ASSERT(c > 0, "incStrong() called on %p after last strong ref", refs);
#if PRINT_REFS
    ALOGD("incStrong of %p from %p: cnt=%d\n", this, id, c);
#endif
    if (c != INITIAL_STRONG_VALUE)  { //判断是否为第一次引用
        return;
    }

    //第一次引用把初始化值减掉
    int32_t old __unused = refs->mStrong.fetch_sub(INITIAL_STRONG_VALUE, std::memory_order_relaxed);
    // A decStrong() must still happen after us.
    ALOG_ASSERT(old > INITIAL_STRONG_VALUE, "0x%x too small", old);
    //给被管理对象的回调接口,第一次引用时回调
    refs->mBase->onFirstRef();
}

// system/core/libutils/RefBase.cpp
void RefBase::weakref_type::incWeak(const void* id)
{
    weakref_impl* const impl = static_cast<weakref_impl*>(this);
    impl->addWeakRef(id); // 由 DEBUG_REFS 控制,release 版本什么也不做
    //弱引用计数加 1
    const int32_t c __unused = impl->mWeak.fetch_add(1,
            std::memory_order_relaxed);
    ALOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

incStrong 中:

  • 调用 incWeak ,弱引用计数 mWeak 加 1
  • 强引用计数 mStrong 加 1
  • 如果是第一次引用,mStrong 减去初始值 INITIAL_STRONG_VALUE

通过以上代码的分析,我们可以看出强引用 sp 的结构如下:

当强引用所在作用域执行完后,就会执行强引用对象的析构函数了:

这里分为两种情况:

  • 强引用控制模式 OBJECT_LIFETIME_STRONG
  • 弱引用控制模式 OBJECT_LIFETIME_WEAK

我们先分析强引用控制模式 OBJECT_LIFETIME_STRONG 下的 sp 析构流程:

// system/core/libutils/include/utils/StrongPointer.h
template<typename T>
sp<T>::~sp() {
    if (m_ptr)
        m_ptr->decStrong(this); //执行被管理对象的 decStrong 函数
}

//接着调用 decStrong
// system/core/libutils/RefBase.cpp
void RefBase::decStrong(const void* id) const
{
    weakref_impl* const refs = mRefs;
    refs->removeStrongRef(id); // 由 DEBUG_REFS 控制,release 版本什么也不做
    // 强引用计数减 1
    // 注意返回值是执行减 1 之前的值
    const int32_t c = refs->mStrong.fetch_sub(1, std::memory_order_release);
#if PRINT_REFS
    ALOGD("decStrong of %p from %p: cnt=%d\n", this, id, c);
#endif
    LOG_ALWAYS_FATAL_IF(BAD_STRONG(c), "decStrong() called on %p too many times",
            refs);
    if (c == 1) { // mStrong 等于 0 了,要执行内存回收操作了
        std::atomic_thread_fence(std::memory_order_acquire);
        //给被管理对象的回调接口
        refs->mBase->onLastStrongRef(id);
        int32_t flags = refs->mFlags.load(std::memory_order_relaxed);
        if ((flags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) { //OBJECT_LIFETIME_STRONG 模式下
            delete this; //回收目标对象内存
        }
    }
    refs->decWeak(id); //弱引用减 1,回收内部对象 weakref_impl
}

// mStrong 减 1 h 后如果等于 0, 就会 delete 目标对象 X,会执行到目标对象的析构函数
RefBase::~RefBase()
{
    int32_t flags = mRefs->mFlags.load(std::memory_order_relaxed);
    
    //强引用走 else 分支
    if ((flags & OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_WEAK) { 
        if (mRefs->mWeak.load(std::memory_order_relaxed) == 0) { 
            delete mRefs; 
        }
    } else if (mRefs->mStrong.load(std::memory_order_relaxed) == INITIAL_STRONG_VALUE) {
     //打印一些信息,不用管
     //......
    }

    //内部 mRefs 指针赋值为 nullptr,防止野指针
    const_cast<weakref_impl*&>(mRefs) = nullptr;
}

//接着执行 decWeak
void RefBase::weakref_type::decWeak(const void* id)
{
    weakref_impl* const impl = static_cast<weakref_impl*>(this);
    impl->removeWeakRef(id);
    // 弱引用计数减 1
    // 注意返回值是执行减 1 之前的值
    const int32_t c = impl->mWeak.fetch_sub(1, std::memory_order_release);
    LOG_ALWAYS_FATAL_IF(BAD_WEAK(c), "decWeak called on %p too many times",
            this);
    if (c != 1) return; //mWeak == 0 了往下执行
    atomic_thread_fence(std::memory_order_acquire);

    int32_t flags = impl->mFlags.load(std::memory_order_relaxed);
    if ((flags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) { //强引用控制
       
        if (impl->mStrong.load(std::memory_order_relaxed) //sp 构造函数中对 mStrong 赋值了,走 else
                == INITIAL_STRONG_VALUE) {
           
            ALOGW("RefBase: Object at %p lost last weak reference "
                    "before it had a strong reference", impl->mBase);
        } else {
            delete impl; // 回收 RefBase 的内部对象 weakref_impl
        }
    } else { //弱引用控制
        impl->mBase->onLastWeakRef(id);
        delete impl->mBase;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81

当 sp 析构时:

  • 调用 decStrong 函数
  • 强引用计数 mStrong 减 1,减 1 后,如果 mStrong 等于 0,就会 delete 目标对象 X
  • 接着调用 decWeak 函数
  • 弱引用计数 mWeak 减 1,减 1 后,如果 mWeak 等于 0,就会 delete 管理对象 weakref_impl

总结一下,在强引用控制模式下:

  • 被管理的对象必须继承自 RefBase
  • RefBase 的成员 weakref_impl* const mRefs 记录了强引用计数值与弱引用计数值
  • 当执行sp 的构造函数时,会调用到 weakref_impl 类的 incStrong 函数, 强引用计数值加 1,弱引用计数值加 1
  • 当 sp 所在作用域指针完毕,执行 sp 的析构函数
    • 强引用减 1,减 1 后强引用计数值为 0,则回收 sp 内部指针 m_ptr 指向的内存(即管理的对象 weakref_impl)
    • 弱引用减 1,减 1 后弱引用计数值为 0,则回收 RefBase 的成员 weakref_impl* const mRefs 指向的内存

可以看出,在强引用控制下,强引用 sp 管理的内存的回收与否是由强引用计数与弱引用计数共同决定的,mStrong 为零时回收目标对象,mWeak 为零时回收管理对象,只有两者同时等于 0,内存才能被完整回收掉。

接着我们分析弱引用控制模式 OBJECT_LIFETIME_WEAK 下的 sp 析构流程:

// system/core/libutils/include/utils/StrongPointer.h
template<typename T>
sp<T>::~sp() {
    if (m_ptr)
        m_ptr->decStrong(this); //执行被管理对象的 decStrong 函数
}

// system/core/libutils/RefBase.cpp
void RefBase::decStrong(const void* id) const
{
    weakref_impl* const refs = mRefs;
    refs->removeStrongRef(id); // 由 DEBUG_REFS 控制,release 版本什么也不做
    // 强引用计数减 1
    // 注意返回值是执行减 1 之前的值
    const int32_t c = refs->mStrong.fetch_sub(1, std::memory_order_release);
#if PRINT_REFS
    ALOGD("decStrong of %p from %p: cnt=%d\n", this, id, c);
#endif
    LOG_ALWAYS_FATAL_IF(BAD_STRONG(c), "decStrong() called on %p too many times",
            refs);
    if (c == 1) { // mStrong 等于 0 了,要执行内存回收操作了
        std::atomic_thread_fence(std::memory_order_acquire);
        //给被管理对象的回调接口
        refs->mBase->onLastStrongRef(id);
        int32_t flags = refs->mFlags.load(std::memory_order_relaxed);
        if ((flags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) { //弱引用模式下不进入 if
            delete this; 
        }
    }
    refs->decWeak(id); //弱引用减 1,
}


//接着执行 decWeak
void RefBase::weakref_type::decWeak(const void* id)
{
    weakref_impl* const impl = static_cast<weakref_impl*>(this);
    impl->removeWeakRef(id);
    // 弱引用计数减 1
    // 注意返回值是执行减 1 之前的值
    const int32_t c = impl->mWeak.fetch_sub(1, std::memory_order_release);
    LOG_ALWAYS_FATAL_IF(BAD_WEAK(c), "decWeak called on %p too many times",
            this);
    if (c != 1) return; //mWeak == 0 了往下执行
    atomic_thread_fence(std::memory_order_acquire);

    int32_t flags = impl->mFlags.load(std::memory_order_relaxed);
    if ((flags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) { 
       
        if (impl->mStrong.load(std::memory_order_relaxed) else
                == INITIAL_STRONG_VALUE) {
           
            ALOGW("RefBase: Object at %p lost last weak reference "
                    "before it had a strong reference", impl->mBase);
        } else {
            delete impl; // 回收 RefBase 的内部对象 weakref_impl
        }
    } else { //弱引用控制,走 else 分支
        impl->mBase->onLastWeakRef(id);
        delete impl->mBase;  //delete 被管理对象
    }
}

// 这里 delete 了被管理对象,会执行到被管理对象的析构函数
RefBase::~RefBase()
{
    int32_t flags = mRefs->mFlags.load(std::memory_order_relaxed);
    
   
    if ((flags & OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_WEAK) { //如果是弱引用控制进入 if
        if (mRefs->mWeak.load(std::memory_order_relaxed) == 0) { //弱引用计数为 0
            delete mRefs; //清理内部管理对象指针
        }
    } else if (mRefs->mStrong.load(std::memory_order_relaxed) == INITIAL_STRONG_VALUE) {
    }

    //内部 mRefs 指针赋值为 nullptr,防止野指针
    const_cast<weakref_impl*&>(mRefs) = nullptr;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79

弱引用控制模式 OBJECT_LIFETIME_WEAK 下 sp 的两个特点:

  • 是否回收对象由弱引用计数 mWeak 是否为 0 单独决定,当 mWeak 等于 0 时,不论 mStrong 是否为 0,目标对象和管理对象均会被回收掉,也就是说,sp 退化为一个普通的引用计数智能指针,引用计数值是 mWeak
  • 目标对象和内部管理对象的回收时间点不同于强引用控制

# 2.3 弱引用源码分析

当我们上一节的示例程序执行到 wp<X> wpX(p); 时,就会执行指针 wp 的构造函数:

// system/core/include/utils/RefBase.h
template<typename T>
wp<T>::wp(T* other)
    : m_ptr(other) //保存指针到 m_ptr
{
    m_refs = other ? m_refs = other->createWeak(this) : nullptr; //增加弱引用计数,wp 内部的 m_refs 指向 createWeak 的返回值(即 RefBase 内部的 mRefs)
}
1
2
3
4
5
6
7

构造函数内部完成了三件事:

  • 保存指针到 m_ptr
  • 调用 createWeak
  • 将 wp 内部的 m_refs 指向 createWeak 的返回值(即 RefBase 内部的 mRefs)

接着我们来看看 createWeak 源码的实现:

// system/core/libutils/RefBase.cpp
RefBase::weakref_type* RefBase::createWeak(const void* id) const
{
    mRefs->incWeak(id); //调用 weakref_impl 的 incWeak
    return mRefs;
}

// system/core/libutils/RefBase.cpp
void RefBase::weakref_type::incWeak(const void* id)
{
    weakref_impl* const impl = static_cast<weakref_impl*>(this);
    impl->addWeakRef(id); // 由 DEBUG_REFS 控制,release 版本什么也不做
    //弱引用计数加 1
    const int32_t c __unused = impl->mWeak.fetch_add(1,
            std::memory_order_relaxed);
    ALOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

以上代码主要操作就是给弱引用计数加 1

接下来示例代码执行到弱引用转强引用的代码:

sp<A> spX2 = wpx.promote()

template<typename T>
sp<T> wp<T>::promote() const
{
    sp<T> result;
    if (m_ptr && m_refs->attemptIncStrong(&result)) {
        result.set_pointer(m_ptr);
    }
    return result;
}

//处理了多种情况与边界条件,无论哪种情况,总结一下就是弱引用加1 强引用加1
bool RefBase::weakref_type::attemptIncStrong(const void* id)
{
    incWeak(id); //弱引用加 1

    //拿到内部管理对象
    weakref_impl* const impl = static_cast<weakref_impl*>(this);
    //拿到强引用计数值
    int32_t curCount = impl->mStrong.load(std::memory_order_relaxed);

    ALOG_ASSERT(curCount >= 0,
            "attemptIncStrong called on %p after underflow", this);

   
    while (curCount > 0 && curCount != INITIAL_STRONG_VALUE) {
        //强引用计数加 1
        if (impl->mStrong.compare_exchange_weak(curCount, curCount+1,
                std::memory_order_relaxed)) {
            break;
        }
    }


    if (curCount <= 0 || curCount == INITIAL_STRONG_VALUE) {

        int32_t flags = impl->mFlags.load(std::memory_order_relaxed);

        if ((flags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) { //强引用计数控制
            if (curCount <= 0) {
                decWeak(id); 
                return false;
            }

            while (curCount > 0) {
                //强引用计数加 1
                if (impl->mStrong.compare_exchange_weak(curCount, curCount+1,
                        std::memory_order_relaxed)) {
                    break;
                }
            }

            if (curCount <= 0) {
                decWeak(id);
                return false;
            }
        } else { //弱引用计数控制
            if (!impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id)) { //始终是 false
                decWeak(id);
                return false;
            }

            //强引用加 1
            curCount = impl->mStrong.fetch_add(1, std::memory_order_relaxed);
            if (curCount != 0 && curCount != INITIAL_STRONG_VALUE) {
                impl->mBase->onLastStrongRef(id);
            }
        }
    }

    impl->addStrongRef(id);

#if PRINT_REFS
    ALOGD("attemptIncStrong of %p from %p: cnt=%d\n", this, id, curCount);
#endif
    // 减掉初始值
    if (curCount == INITIAL_STRONG_VALUE) {
        impl->mStrong.fetch_sub(INITIAL_STRONG_VALUE,
                std::memory_order_relaxed);
    }

    return true;
}


template<typename T>
void sp<T>::set_pointer(T* ptr) {
    m_ptr = ptr;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90

promote() 函数处理了多种情况与边界条件,无论哪种情况,总结一下就是弱引用计数加 1 强引用计数加 1

当弱引用所在作用域执行完后,就会执行弱引用对象的析构函数了:

// system/core/include/utils/RefBase.h
template<typename T>
wp<T>::~wp()
{
    if (m_ptr) m_refs->decWeak(this); //指针内部对象的 decWeak 函数
}

//接着执行 decWeak
void RefBase::weakref_type::decWeak(const void* id)
{
    weakref_impl* const impl = static_cast<weakref_impl*>(this);
    impl->removeWeakRef(id);
    // 弱引用计数减 1
    // 注意返回值是执行减 1 之前的值
    const int32_t c = impl->mWeak.fetch_sub(1, std::memory_order_release);
    LOG_ALWAYS_FATAL_IF(BAD_WEAK(c), "decWeak called on %p too many times",
            this);
    if (c != 1) return; // mWeak == 0 往下执行
    atomic_thread_fence(std::memory_order_acquire);

    int32_t flags = impl->mFlags.load(std::memory_order_relaxed);
    if ((flags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) { //强引用控制
       
        if (impl->mStrong.load(std::memory_order_relaxed)
                == INITIAL_STRONG_VALUE) { //没有强引用指向目标对象
           
            ALOGW("RefBase: Object at %p lost last weak reference "
                    "before it had a strong reference", impl->mBase);
        } else { 
            delete impl; // 回收 RefBase 的内部对象 weakref_impl
        }
    } else { //弱引用控制
        impl->mBase->onLastWeakRef(id);
        delete impl->mBase; //回收目标对象,进而执行到 RefBase 的析构函数

    }
}

RefBase::~RefBase()
{
    int32_t flags = mRefs->mFlags.load(std::memory_order_relaxed);
    

    if ((flags & OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_WEAK) {  //弱引用控制则进入 if
        if (mRefs->mWeak.load(std::memory_order_relaxed) == 0) { 
            delete mRefs; 
        }
    } else if (mRefs->mStrong.load(std::memory_order_relaxed) == INITIAL_STRONG_VALUE) {
     //打印一些信息,不用管
     //......
    }

    //内部 mRefs 指针赋值为 nullptr,防止野指针
    const_cast<weakref_impl*&>(mRefs) = nullptr;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55

析构函数中,弱引用计数减 1 ,减1后,如果弱引用计数等于 0 则:

  • 强引用控制: 回收管理对象 weakref_impl,目标对象并没有被回收,说明在强引用模式下 wp 不能单独使用,必须结合在作用域结束前与与一个 sp 联系起来(构造函数,promote 函数等)
  • 弱引用控制: 回收目标对象,进而执行到 RefBase 的析构函数,析构函数中回收管理对象 weakref_impl,说明在弱引用模式下,wp 是可以单独使用的,进化为一个普通的引用计数指针,引用计数值是 mWeak。

# 总结

智能指针的基本原理和使用是非常简单的,Android 平台智能指针的实现略显繁琐,主要原因是增加了弱引用支持以及对各类边界情况的处理。我们需要熟练掌握智能指针的使用,了解智能指针初始化和析构的主干流程,如果在实践中遇到相关问题,再深入源码,分析各类边界情况。

# 参考资料

# 关于

我叫阿豪,2015 年本科毕业于国防科学技术大学指挥信息系统专业,毕业后从事信息化装备的研发工作,工作内容主要涉及 Android Framework 与 Linux Kernel。

如果你对 Android Framework 感兴趣或者正在学习 Android Framework,可以关注我的微信公众号和抖音,我会持续分享我的学习经验,帮助正在学习的你少走一些弯路。学习过程中如果你有疑问或者你的经验想要分享给大家可以添加我的微信,我拉你进技术交流群。